/*
 * C4.8.2.c
 *
 *  Created on: 2012/08/21
 *      Author: owner
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rule_info.h"
#include "core.h"
#include "trace.h"

static const PSZ RuleID = "C4.8.2";

#define FLAG_LEFT	1
#define FLAG_RIGHT	2
#define FLAG_BOTH	3

static const PSZ MESSAGE_ENG = "'%s' Operator's %s operand is signed type";
static const PSZ MESSAGE_CHS = "'%s'演算子的%s操作数是带符号的型";
static const PSZ MESSAGE_JPN = "'%s'演算子の%sオペランドは符号付の型";

static const U2 RANK = MSG_RANK_ERR;

static PRULEOUT pRuleHead;
static PRULEOUT pRuleTail;

/******************************************************************
 * static function:
 * checkLeftExp
 *******************************************************************/
static INT checkLeftExp(AST cmdIndex) {
	INT result = 0;
	AST leftOpIndex = 0;
	AST leftCmd = 0;
	AST leftTypeInfo = 0;
	leftOpIndex = LinkCommandList.getLeftOperand(cmdIndex);
	leftCmd = LinkOperand.getParameter(leftOpIndex);
	leftTypeInfo = LinkCommandList.getType(leftCmd);
	if (LinkTypeInfo.isSigned(leftTypeInfo)) {
		result = RULE_RESULT_NG;
	} else {
		result = RULE_RESULT_OK;
	}
	return result;
}

/******************************************************************
 * static function:
 * checkRightExp
 *******************************************************************/
static INT checkRightExp(AST cmdIndex) {
	INT result = 0;
	AST rightOpIndex = 0;
	AST rightCmd = 0;
	AST rightTypeInfo = 0;
	rightOpIndex = LinkCommandList.getRightOperand(cmdIndex);
	rightCmd = LinkOperand.getParameter(rightOpIndex);
	rightTypeInfo = LinkCommandList.getType(rightCmd);
	if (LinkTypeInfo.isSigned(rightTypeInfo)) {
		result = RULE_RESULT_NG;
	} else {
		result = RULE_RESULT_OK;
	}
	return result;
}

/******************************************************************
 * main logic
 *******************************************************************/
static S4 RuleMain(AST cmdIndex, U4 event) {

	INT result = RULE_RESULT_OK;
	INT lResult = 0;
	INT rResult = 0;
	PRULEOUT newNode = NULL;
	PRULEOUT tmpNode = NULL;
	PRULEOUT tmpNode1 = NULL;
	PSZ opName = NULL;
	INT lrFlag = 0;

	if (!(event & EVENT_CMDLIST_PREV)) {
		return EXIT_SUCCESS;
	}

	/*check logic*/
	/*~*/
	if (LinkCommandList.isBitNegation(cmdIndex)) {
		result = checkLeftExp(cmdIndex);
		if (result == RULE_RESULT_NG) {
			opName = "~";
			lrFlag = FLAG_LEFT;
		}
	}
	/*<<*/
	else if (LinkCommandList.isLeftShift(cmdIndex)) {
		result = checkLeftExp(cmdIndex);
		if (result == RULE_RESULT_NG) {
			opName = "&lt;&lt;";
			lrFlag = FLAG_LEFT;
		}
	}
	/*>>*/
	else if (LinkCommandList.isRightShift(cmdIndex)) {
		result = checkLeftExp(cmdIndex);
		if (result == RULE_RESULT_NG) {
			opName = ">>";
			lrFlag = FLAG_LEFT;
		}
	}
	/*&*/
	else if (LinkCommandList.isBitAnd(cmdIndex)) {
		lResult = checkLeftExp(cmdIndex);
		rResult = checkRightExp(cmdIndex);
		if (lResult == RULE_RESULT_NG && rResult == RULE_RESULT_OK) {
			result = RULE_RESULT_NG;
			opName = "&amp;";
			lrFlag = FLAG_LEFT;
		} else if (lResult == RULE_RESULT_OK && rResult == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
			opName = "&amp;";
			lrFlag = FLAG_RIGHT;
		} else if (lResult == RULE_RESULT_NG && rResult == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
			opName = "&amp;";
			lrFlag = FLAG_BOTH;
		} else {
			result = RULE_RESULT_OK;
		}
	}
	/*|*/
	else if (LinkCommandList.isBitInclusiveOr(cmdIndex)) {
		lResult = checkLeftExp(cmdIndex);
		rResult = checkRightExp(cmdIndex);
		if (lResult == RULE_RESULT_NG && rResult == RULE_RESULT_OK) {
			result = RULE_RESULT_NG;
			opName = "|";
			lrFlag = FLAG_LEFT;
		} else if (lResult == RULE_RESULT_OK && rResult == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
			opName = "|";
			lrFlag = FLAG_RIGHT;
		} else if (lResult == RULE_RESULT_NG && rResult == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
			opName = "|";
			lrFlag = FLAG_BOTH;
		} else {
			result = RULE_RESULT_OK;
		}
	}
	/*^*/
	else if (LinkCommandList.isBitExclusiveOr(cmdIndex)) {
		lResult = checkLeftExp(cmdIndex);
		rResult = checkRightExp(cmdIndex);
		if (lResult == RULE_RESULT_NG && rResult == RULE_RESULT_OK) {
			result = RULE_RESULT_NG;
			opName = "^";
			lrFlag = FLAG_LEFT;
		} else if (lResult == RULE_RESULT_OK && rResult == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
			opName = "^";
			lrFlag = FLAG_RIGHT;
		} else if (lResult == RULE_RESULT_NG && rResult == RULE_RESULT_NG) {
			result = RULE_RESULT_NG;
			opName = "^";
			lrFlag = FLAG_BOTH;
		} else {
			result = RULE_RESULT_OK;
		}
	}
	/*other*/
	else {
		return EXIT_SUCCESS;
	}

	if (result == RULE_RESULT_OK) {
		return EXIT_SUCCESS;
	}

	/*re-checked?*/
	tmpNode = pRuleHead;
	while (tmpNode != NULL ) {
		if (tmpNode->indexInfo == cmdIndex) {
			if (result == RULE_RESULT_NG) {
				result = RULE_RESULT_OK;
			} else {
				if (tmpNode == pRuleHead) {
					pRuleHead = pRuleHead->next;
					free(tmpNode);
				} else if (tmpNode == pRuleTail) {
					tmpNode1->next = NULL;
					pRuleTail = tmpNode1;
					free(tmpNode);
				} else {
					tmpNode1->next = tmpNode->next;
					free(tmpNode);
				}
			}
			break;
		}
		tmpNode1 = tmpNode;
		tmpNode = tmpNode->next;
	}

	/*make result struct*/
	if (result == RULE_RESULT_NG) {
		newNode = (PRULEOUT) malloc(sizeof(RULEOUT));
		if (pRuleHead == NULL ) {
			pRuleHead = newNode;
		}

		newNode->indexInfo = cmdIndex;
		newNode->fileIndex = CCodeScope.getFileIndex(
				LinkCommandList.getCodeScope(cmdIndex));
		newNode->beginLine = CCodeScope.getBeginLine(
				LinkCommandList.getCodeScope(cmdIndex));
		newNode->beginCol = CCodeScope.getBeginLineOffset(
				LinkCommandList.getCodeScope(cmdIndex));
		newNode->endLine = CCodeScope.getEndLine(
				LinkCommandList.getCodeScope(cmdIndex));
		newNode->endCol = CCodeScope.getEndLineOffset(
				LinkCommandList.getCodeScope(cmdIndex));
		newNode->ruleID = RuleID;
		newNode->errRank = RANK;

		if (lrFlag == FLAG_LEFT) {
			sprintf(newNode->msgBuf_eng, MESSAGE_ENG, opName, "left");
			sprintf(newNode->msgBuf_chs, MESSAGE_CHS, opName, "左");
			sprintf(newNode->msgBuf_jpn, MESSAGE_JPN, opName, "左");
		} else if (lrFlag == FLAG_RIGHT) {
			sprintf(newNode->msgBuf_eng, MESSAGE_ENG, opName, "right");
			sprintf(newNode->msgBuf_chs, MESSAGE_CHS, opName, "右");
			sprintf(newNode->msgBuf_jpn, MESSAGE_JPN, opName, "右");
		} else if (lrFlag == FLAG_BOTH) {
			sprintf(newNode->msgBuf_eng, MESSAGE_ENG, opName, "left and right");
			sprintf(newNode->msgBuf_chs, MESSAGE_CHS, opName, "左右两边");
			sprintf(newNode->msgBuf_jpn, MESSAGE_JPN, opName, "左右両方");
		}

		newNode->rfileIndex = 0;
		newNode->rlocLine = 0;
		newNode->next = NULL;

		if (pRuleTail != NULL ) {
			pRuleTail->next = newNode;
		}

		pRuleTail = newNode;
	}

	return EXIT_SUCCESS;
}

VOID C4_8_2_register(VOID) {
	PRULEMAN * pCurRule = &stRuleManager;
	PRULEMAN newRuleMan = (PRULEMAN) malloc(sizeof(RULEMAN));
	memset(newRuleMan, 0, sizeof(RULEMAN));
	newRuleMan->ruleID = RuleID;
	newRuleMan->ruleSwitch = OFF;
	newRuleMan->headOut = &pRuleHead;
	newRuleMan->tailOut = &pRuleTail;
	newRuleMan->ruleMain_cmd = RuleMain;
	newRuleMan->ruleMain_ast = NULL;
	newRuleMan->nextRule = NULL;
	if (stRuleManager == NULL ) {
		stRuleManager = newRuleMan;
	} else {
		while ((*pCurRule)->nextRule != NULL ) {
			pCurRule = &((*pCurRule)->nextRule);
		}
		(*pCurRule)->nextRule = newRuleMan;
	}
}
